package com.algorithm.example.queue.blockingQueue;

import java.util.Arrays;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * <p>
 * 测试线程不安全
 * </p>
 * 1.synchronized 关键字，功能少
 * 2.ReentrantLock 可重入锁，功能多
 *
 * @author lzt
 * @version 1.0
 * @since 2024/1/28 17:04
 */
public class TestThreadUnsafe {
    private final String[] array = new String[10];
    private int tail = 0;
    private int size = 0;
    ReentrantLock lock = new ReentrantLock(); // 锁对象
    Condition tailWaits = lock.newCondition(); // 条件变量对象 集合

    public void offer(String e) throws InterruptedException {
//        lock.lock();  // 加锁
        lock.lockInterruptibly(); // 加锁(可以在阻塞状态随时打断)
        try {
            while (isFull()) {
                // 满了需要处理的事情
                // 当前线程加入 tailWaits ，并且让此线程阻塞 tailWaits.signal()
                // 唤醒之后需要检查条件，不然就是虚假唤醒
                tailWaits.await();
            }
            array[tail] = e;
            if(++tail == array.length) {
                tail = 0;
            }
            size++;
        } finally {
            lock.unlock(); // 解锁
        }
    }

    public boolean isFull() {
        return size == array.length;
    }

    @Override
    public String toString() {
        return "TestThreadUnsafe{" +
                "array=" + Arrays.toString(array) +
                ", tail=" + tail +
                '}';
    }

    public static void main(String[] args) throws InterruptedException {
        TestThreadUnsafe q = new TestThreadUnsafe();
        for (int i = 0; i < 10; i++) {
            q.offer("e" + i);
        }
        new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + "添加元素之前");
                q.offer("e10");
                System.out.println(Thread.currentThread().getName() + "添加元素之后");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, "e1").start();
        new Thread(() -> {
            System.out.println("开始唤醒");
            try {
                q.lock.lockInterruptibly();
                q.tailWaits.signal();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                q.lock.unlock();
            }
        }, "e2").start();
    }

}
